from threading import Thread
from main.shortTermSchedulers import Scheduler_ShortestJobFirst_E

class Kernel(Thread):
    def __init__(self,aLongTermScheduler,aShortTermScheduler,aCPU,anArrivingProcessesQueue,aReadyProcessesQueue,aFinishedProcessesQueue,aMemory,aDisk):
        Thread.__init__(self)
        self.arrivingProcessesQueue = anArrivingProcessesQueue
        self.readyProcessesQueue = aReadyProcessesQueue
        self.longTermScheduler = aLongTermScheduler
        self.shortTermScheduler = aShortTermScheduler
        self.finishedProcessesQueue = aFinishedProcessesQueue
        self.cpu = aCPU
        self.interruptionForExpropiationFlag = False
        self.needsToShutdown = False
        self.memory = aMemory
        self.disk = aDisk
        self.processesInSystem = []
        
    def sendPrepareToShutdownSignal(self):
        self.needsToShutdown = True  
    
    def prepareToShutDown(self):  
        pass #ACA PREPARO TODO PARA APAGARME
    
    def needsToExpropiate(self):
        return self.interruptionForExpropiationFlag
    
    def isNotInKernelMode(self):
        return ((not self.needsToShutdown) and (not self.needsToExpropiate()))

#-------RUN-------------------------------------------#

    def run(self):
        while(True):
            while(self.isNotInKernelMode()):
            #Si puedo trabajar (mirar "isNotInKernelMode()"), trabajo
                if(self.cpu.isNotWorking()): #PERO SOLO SI LA CPU PUEDE TRABAJAR!si puede recibir a un proceso :D
                    if(not self.arrivingProcessesQueue.isEmpty()): #y si hay programas
                        self.longTermScheduler.dispatchAProcess(self.memory,self.disk) #el PLP pone un programa/proceso en la cola de listos
                    if(not self.readyProcessesQueue.isEmpty()): #si hay procesos listos a ser despahcados
                        self.shortTermScheduler.dispatchAProcess() #el PCP pone un proceso en la CPU
                        print('Se han despachado un proceso por el STS')
            if(self.needsToExpropiate()): #SI LLEGUE ACA ES PORQUE QUIERO EXPROPIAR (VER "needsToExpropiate()")
                self.cpu.expropiate()
                self.restoreUserMode()
            if(self.needsToShutdown): # ME FIJO SI ME QUIERO APAGAR POR LAS DUDAS
                self.prepareToShutDown()
    

#-------INTERRUPTIONS----------------------------------#
        
    def interrupt_processFinishedIOInstruction(self,aProcess):
        print('Kernel interruption: a process '+str(aProcess.pcb.processID)+' has finished IO execution')
        if(not aProcess.pcb.currentInstruction == None):
            self.readyProcessesQueue.append(aProcess)
        else:
            self.interrupt_aProcessHasEnded(aProcess)
  

    
    def interrupt_newProcessArrived(self,aProcess):
        print('Kernel interruption: new process arrived to System')
        self.arrivingProcessesQueue.append(aProcess)
        self.processesInSystem.append(aProcess)
    
    # SOLO FUNCIONA CON SJF_E
    def interrupt_processArrivedToRPQ(self,aProcess):
        print('Kernel interruption:  process '+str(aProcess.pcb.processID)+' arrived to RPQ')
        if(type(self.shortTermScheduler)==Scheduler_ShortestJobFirst_E):
            if(self.shortTermScheduler.needToExpropiate()):
                self.interruptionForExpropiationFlag = True
        
    def interrupt_aProcessHasEnded(self,aProcess):
        print('Kernel interruption: a process '+str(aProcess.pcb.processID)+' has finished his total execution')
        self.removeFinishedProcessFromExecution(aProcess)
        #self.processesInSystem.remove(aProcess)
            
    def interrupt_quantumFinished(self):
        self.interruptionForExpropiationFlag = True
        
#------------------------------------------------------#

    def restoreUserMode(self):
        self.interruptionForExpropiationFlag = False
        
    def removeFinishedProcessFromExecution(self,aProcess):
        self.finishedProcessesQueue.append(aProcess)
        self.memory.quitProcessOfMemory(aProcess)
       
            
    
        
    